﻿Public Class ContentReference
    Inherits MysteryPropertyAttribute


    Public Property label As String

    Private _tableName As String

    Public ReadOnly Property tableName As String
        Get
            'done in a second step to avoid recursion on intial registration
            If String.IsNullOrEmpty(_tableName) Then setTablename()
            Return _tableName
        End Get
    End Property

    Private Sub setTablename()
        Dim ct As ContentType = Me.used_in.DeclaringType.getMysteryAttribute(Of ContentType)()
        _tableName = ct.name & name
    End Sub


    Public Overrides Sub setup()
        If String.IsNullOrEmpty(label) Then label = name

    End Sub

End Class

Public MustInherit Class BaseContentReference
    Inherits ContentPropertyValue

    Public MustOverride Sub add(item As IContent)
    Public MustOverride Sub setWithGuids(items As IEnumerable(Of Guid))
    Public MustOverride Function getAsGuidEnum() As IEnumerable(Of Guid)
    Public MustOverride Function getAsEnum() As IEnumerable(Of IContent)
    Public MustOverride Sub setWithEnum(contents As IEnumerable(Of IContent))

End Class

Public Class SingleContentReference(Of T As IContent)
    Inherits BaseContentReference

    Private _value As T
    Private _guid As Guid?

    Public Property value As T
        Get
            If _guid IsNot Nothing Then
                _value = getGlobalObject(Of IContentDispatcher)().getContent(Of T)(_guid)
                _guid = Nothing
            End If
            Return _value
        End Get
        Set(value As T)
            _value = value
            _guid = Nothing
        End Set
    End Property

    Public Sub New()

    End Sub

    Public Sub New(value As T)
        Me.value = value
    End Sub

    Public Shared Widening Operator CType(ByVal initialData As T) As SingleContentReference(Of T)
        Return New SingleContentReference(Of T) With {.value = initialData}
    End Operator

    Public Shared Narrowing Operator CType(ByVal initialData As SingleContentReference(Of T)) As T
        If initialData Is Nothing Then Return Nothing
        Return initialData.value
    End Operator

    Public Overrides Function getValue() As Object
        Return value
    End Function

    Public Overrides Function isFilter() As Boolean
        Return False
    End Function

    Public Overrides Function ToString() As String
        If value Is Nothing Then Return Nothing
        Return value.ToString()

    End Function

    Public Overrides Sub add(item As IContent)
        If item Is Nothing Then Exit Sub
        Me.value = item
    End Sub

    Public Overrides Sub setValue(value As Object)
        Me.value = value
    End Sub

    Public Overrides Sub setWithGuids(items As IEnumerable(Of System.Guid))
        If items Is Nothing Then
            _guid = Nothing
            _value = Nothing
            Exit Sub
        End If
        Dim value As Guid = items.FirstOrDefault
        If Guid.Empty = value Then
            _guid = Nothing
            _value = Nothing
            Exit Sub
        End If

        _guid = value

    End Sub

    Public Overrides Function getAsGuidEnum() As System.Collections.Generic.IEnumerable(Of System.Guid)
        If _guid IsNot Nothing Then
            Return New List(Of Guid) From {_guid}
        End If
        If value Is Nothing Then Return New List(Of Guid)
        Return New List(Of Guid) From {value.guid}
    End Function

    Public Overrides Function getAsEnum() As System.Collections.Generic.IEnumerable(Of IContent)
        Dim result As New List(Of IContent)(1)
        If value IsNot Nothing Then
            result.Add(value)
        End If
        Return result
    End Function

    Public Overrides Sub setWithEnum(contents As System.Collections.Generic.IEnumerable(Of IContent))
        If contents Is Nothing OrElse contents.Count = 0 Then
            value = Nothing
            Exit Sub
        End If
        Dim new_value As T = contents.FirstOrDefault
        Me.value = new_value
    End Sub
End Class

Public Class MultiContentReference(Of T As IContent)
    Inherits BaseContentReference

    Private _value As New List(Of T)
    Private _guid As ICollection(Of Guid)

    Public ReadOnly Property value As IEnumerable(Of T)
        Get
            If _guid IsNot Nothing Then
                Dim cd As IContentDispatcher = getGlobalObject(Of IContentDispatcher)()
                Dim contents As IEnumerable(Of T) = (From x As Guid In _guid Select cd.getContent(Of T)(x))
                _value = New List(Of T)(From x As T In contents Select x Where x IsNot Nothing)
                _guid = Nothing
            End If
            Return _value.AsReadOnly
        End Get
    End Property

    Public Sub New()

    End Sub

    Public Sub New(value As IEnumerable(Of T))
        If value IsNot Nothing Then Me._value = New List(Of T)(value)
    End Sub

    Public Shared Widening Operator CType(ByVal initialData As List(Of T)) As MultiContentReference(Of T)
        Return New MultiContentReference(Of T)(initialData)
    End Operator
    Public Shared Widening Operator CType(ByVal initialData As HashSet(Of T)) As MultiContentReference(Of T)
        Return New MultiContentReference(Of T)(initialData)
    End Operator
    Public Shared Widening Operator CType(ByVal initialData As LinkedList(Of T)) As MultiContentReference(Of T)
        Return New MultiContentReference(Of T)(initialData)
    End Operator

    Public Shared Narrowing Operator CType(ByVal initialData As MultiContentReference(Of T)) As List(Of T)
        If initialData Is Nothing Then Return Nothing
        Return New List(Of T)(initialData._value)
    End Operator
    Public Shared Narrowing Operator CType(ByVal initialData As MultiContentReference(Of T)) As HashSet(Of T)
        If initialData Is Nothing Then Return Nothing
        Return New HashSet(Of T)(initialData._value)
    End Operator
    Public Shared Narrowing Operator CType(ByVal initialData As MultiContentReference(Of T)) As LinkedList(Of T)
        If initialData Is Nothing Then Return Nothing
        Return New LinkedList(Of T)(initialData._value)
    End Operator

    Public Overrides Function getValue() As Object
        Return value
    End Function

    Public Overrides Function isFilter() As Boolean
        Return False
    End Function

    Public Overrides Function ToString() As String
        If value Is Nothing Then Return Nothing
        Return value.ToString()

    End Function

    Public Overrides Sub add(item As IContent)
        If item Is Nothing Then Exit Sub
        If _guid IsNot Nothing Then
            _guid.Add(item.guid)
            Exit Sub
        End If
        Me._value.Add(item)
    End Sub

    Public Overrides Sub setValue(value As Object)
        Dim as_enu As IEnumerable(Of T) = value
        Me._value = New List(Of T)(as_enu)
    End Sub

    Public Overrides Sub setWithGuids(items As IEnumerable(Of System.Guid))
        If items Is Nothing Then Exit Sub
        _guid = New List(Of Guid)(items)
    End Sub

    Public Overrides Function getAsGuidEnum() As System.Collections.Generic.IEnumerable(Of System.Guid)
        If _guid IsNot Nothing Then
            Return New List(Of Guid)(_guid)
        End If
        Return New List(Of Guid)(From x As T In value Select x.guid)
    End Function

    Public Overrides Function getAsEnum() As System.Collections.Generic.IEnumerable(Of IContent)
        Return value
    End Function

    Public Overrides Sub setWithEnum(contents As IEnumerable(Of IContent))
        _guid = Nothing

        If contents Is Nothing Then
            _value = New List(Of T)
        Else
            _value = New List(Of T)(From x As T In contents Select x)
        End If

    End Sub
End Class

Public Class ContentPropertySingleReferenceFilter(Of T As IContent)
    Inherits SingleContentReference(Of T)
    Implements IContentPropertyFilter

    Public Property values As ICollection(Of T) = New HashSet(Of T)

    Public Sub New()

    End Sub

    Public Sub New(value As T)
        Me.value = value
    End Sub

    Public Sub New(values As IEnumerable(Of T))
        Me.values = New HashSet(Of T)(values)
    End Sub


    Public Overrides Function isFilter() As Boolean
        Return True
    End Function

    Public Function doesMatch(value_to_match As ContentPropertyValue) As Boolean Implements IContentPropertyFilter.doesMatch
        Dim typed_value As T = If(value_to_match Is Nothing, Nothing, value_to_match.getValue())
        If values Is Nothing OrElse values.Count = 0 Then
            If value Is Nothing AndAlso typed_value Is Nothing Then Return True
            If value Is Nothing AndAlso typed_value IsNot Nothing Then Return False
            If typed_value Is Nothing Then Return False
            Return Me.value.Equals(typed_value)
        End If
        Return Me.values.Contains(typed_value)
    End Function

    Public Function getValues() As System.Collections.Generic.IEnumerable(Of Object) Implements IContentPropertyFilter.getValues
        If values Is Nothing OrElse values.Count = 0 Then
            Return New HashSet(Of Object) From {value}
        End If
        Return New HashSet(Of Object)(From x As Object In values Select x)
    End Function


    Public Sub setValues(input As System.Collections.Generic.IEnumerable(Of Object)) Implements IContentPropertyFilter.setValues
        Dim cd As IContentDispatcher = getGlobalObject(Of IContentDispatcher)()
        For Each v As Object In input
            Dim s As String = v
            Dim c_guid As Guid = Guid.Parse(s)
            Me.values.Add(cd.getContent(Of IContent)(c_guid))
        Next
    End Sub

End Class

Public Class ContentPropertyMultiReferenceFilter(Of T As IContent)
    Inherits MultiContentReference(Of T)
    Implements IContentPropertyFilter

    Public Property values As ICollection(Of T) = New HashSet(Of T)

    Public Sub New()

    End Sub

    Public Sub New(values As IEnumerable(Of T))
        Me.values = New HashSet(Of T)(values)
    End Sub


    Public Overrides Function isFilter() As Boolean
        Return True
    End Function

    Public Function doesMatch(value_to_match As ContentPropertyValue) As Boolean Implements IContentPropertyFilter.doesMatch
        Dim typed_value As T = If(value_to_match Is Nothing, Nothing, value_to_match.getValue())
        If values Is Nothing OrElse values.Count = 0 Then
            If value Is Nothing AndAlso typed_value Is Nothing Then Return True
            If value Is Nothing AndAlso typed_value IsNot Nothing Then Return False
            If typed_value Is Nothing Then Return False
            Return Me.value.Equals(typed_value)
        End If
        Return Me.values.Contains(typed_value)
    End Function

    Public Function getValues() As System.Collections.Generic.IEnumerable(Of Object) Implements IContentPropertyFilter.getValues
        If values Is Nothing OrElse values.Count = 0 Then
            Return New HashSet(Of Object) From {value}
        End If
        Return New HashSet(Of Object)(From x As Object In values Select x)
    End Function

    Public Sub setValues(input As System.Collections.Generic.IEnumerable(Of Object)) Implements IContentPropertyFilter.setValues
        Dim cd As IContentDispatcher = getGlobalObject(Of IContentDispatcher)()
        For Each v As Object In input
            Dim s As String = v
            Dim c_guid As Guid = Guid.Parse(s)
            Me.values.Add(cd.getContent(Of IContent)(c_guid))
        Next
    End Sub
End Class